﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Shared
{
    public enum LogType
    {
        Fatal,
        Error,
        Warning,
        Notice,
        User
    }

    public class LogHandler
    {
        #region Fields

        /// <summary>
        /// Calling module name.
        /// </summary>
        private string Module;

        /// <summary>
        /// Writer for the log file.
        /// </summary>
        private StreamWriter Writer;

        /// <summary>
        /// Syncronizing object for log operations.
        /// </summary>
        private object Sync = new object();

        /// <summary>
        /// Syncronizing object for packet dumping.
        /// </summary>
        private object PacketSync = new object();

        #endregion

        #region Construct / Destruct

        /// <summary>
        /// Constructs a new log handler.
        /// </summary>
        /// <param name="Module">Name of the calling server module.</param>
        public LogHandler(string Module)
        {
            this.Module = Module;
            this.Refresh();
        }

        #endregion

        #region Methods

        #region Operations

        /// <summary>
        /// Refreshes the log writer and saves current log data.
        /// </summary>
        private void Refresh()
        {
            string LogDirectory = "Logs\\" + DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString().PadLeft(2, '0') + DateTime.Now.Day.ToString().PadLeft(2, '0') + "\\";

            if (!Directory.Exists(LogDirectory))
            {
                Directory.CreateDirectory(LogDirectory);
            }

            lock (this.Sync)
            {
                if (this.Writer != null)
                {
                    this.Writer.Close();
                }

                this.Writer = new StreamWriter(LogDirectory + this.Module + ".log", true);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Writes to log and outputs.
        /// </summary>
        /// <param name="Type">Type of the log message.</param>
        /// <param name="LogString">The log message.</param>
        /// <param name="Arguments">Format arguments for log message.</param>
        public void Write(LogType Type, string LogString, params object[] Arguments)
        {
            LogString = String.Format(LogString, Arguments);

            string LogTime = DateTime.Now.TimeOfDay.ToString().Substring(0, 8);
            string LogTag = "[Unknown]";
            ConsoleColor Color = ConsoleColor.Gray;

            switch (Type)
            {
                case LogType.User:
                    {
                        Color = ConsoleColor.Cyan;
                        LogTag = "[User]";
                    }
                    break;

                case LogType.Fatal:
                    {
                        Color = ConsoleColor.Red;
                        LogTag = "[Fatal]";
                    }
                    break;

                case LogType.Error:
                    {
                        Color = ConsoleColor.Red;
                        LogTag = "[Error]";
                    }
                    break;

                case LogType.Warning:
                    {
                        Color = ConsoleColor.Yellow;
                        LogTag = "[Warning]";
                    }
                    break;

                case LogType.Notice:
                    {
                        Color = ConsoleColor.Green;
                        LogTag = "[Notice]";
                    }
                    break;
            }

            // Output.
            {
                Console.Write("[" + LogTime + "] ");

                Console.ForegroundColor = Color;
                Console.Write(LogTag);
                Console.ResetColor();

                Console.Write(" " + LogString + "\r\n");
            }

            // Log.
            {
                lock (this.Sync)
                {
                    this.Writer.WriteLine("[" + LogTime + "] " + LogTag + " " + LogString);
                }
            }

            // Refresh to prevent data-loss.
            this.Refresh();
        }

        /// <summary>
        /// Dumps an exception into the log.
        /// </summary>
        /// <param name="e">Exception to be dumped.</param>
        public void Crash(Exception e)
        {
            Write(LogType.Fatal, e.ToString());
        }

        /// <summary>
        /// Dumps a packet into a bin file.
        /// </summary>
        /// <param name="Packet">Packet to dump.</param>
        public void DumpPacket(int Header, DataPacket Packet)
        {
            BinaryWriter Dumper = new BinaryWriter(new FileStream("packets\\0x" + Header.ToString("X8") + ".bin", FileMode.Create));

            Dumper.Write(Packet.Buffer);

            Dumper.Close();
        }

        #endregion

        #endregion
    }
}
